curl --request POST \
--url https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{}'import requests
url = "https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release"
payload = {}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({})
};
fetch('https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release"
payload := strings.NewReader("{}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{}"
response = http.request(request)
puts response.read_body{
"resource": {
"type": "Hold",
"id": 142,
"qty": 12,
"held_at": "2026-04-28T14:32:00Z",
"status": "active",
"merchant": {
"type": "Merchant",
"id": 4
},
"warehouse": {
"type": "Warehouse",
"id": 123
},
"product": {
"id": 123
},
"location": {
"type": "Location",
"id": 42
},
"lot": {
"type": "Lot",
"id": 54
},
"reason": {
"code": "damaged",
"label": "Damaged",
"parent_code": "damaged"
},
"held_by": {
"type": "Requester",
"id": 3
},
"released_at": null,
"released_by": {
"type": "Requester",
"id": 3
},
"notes": "Damaged in receiving",
"updated_at": "2026-04-28T14:32:00Z"
}
}{
"errors": [
{
"type": "not_found",
"message": "The server could not find the requested resource."
}
]
}{
"errors": [
{
"type": "unable_to_process",
"message": "The supplied parameters are invalid.",
"details": [
{
"key": "hold_until_date",
"message": "The date must be in the future."
}
]
}
]
}Release one Hold by ID
Releases a single active stock_hold row by its id.
curl --request POST \
--url https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{}'import requests
url = "https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release"
payload = {}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({})
};
fetch('https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release"
payload := strings.NewReader("{}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{base_url_domain}/api/global/v1/inventory/holds/{id}/release")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{}"
response = http.request(request)
puts response.read_body{
"resource": {
"type": "Hold",
"id": 142,
"qty": 12,
"held_at": "2026-04-28T14:32:00Z",
"status": "active",
"merchant": {
"type": "Merchant",
"id": 4
},
"warehouse": {
"type": "Warehouse",
"id": 123
},
"product": {
"id": 123
},
"location": {
"type": "Location",
"id": 42
},
"lot": {
"type": "Lot",
"id": 54
},
"reason": {
"code": "damaged",
"label": "Damaged",
"parent_code": "damaged"
},
"held_by": {
"type": "Requester",
"id": 3
},
"released_at": null,
"released_by": {
"type": "Requester",
"id": 3
},
"notes": "Damaged in receiving",
"updated_at": "2026-04-28T14:32:00Z"
}
}{
"errors": [
{
"type": "not_found",
"message": "The server could not find the requested resource."
}
]
}{
"errors": [
{
"type": "unable_to_process",
"message": "The supplied parameters are invalid.",
"details": [
{
"key": "hold_until_date",
"message": "The date must be in the future."
}
]
}
]
}Authorizations
Generate a JWT access token through a Custom Global Integration and provide it with each request in the Authorization header prefixed with "Bearer" and then a single space.
Path Parameters
hold_id to release.
Body
Empty object {}. The engine's Hold::release() does not currently accept release-time
notes — the notes set when the hold was placed is preserved in the audit history.
The body is of type object.
Response
Hold released.
An inventory hold record. Cross-merchant view (Global API surface).
Releasing cascaded holds: when holdLot is called with cascade_bom=true, free the
cascade tree by releasing each child via POST /holds/{id}/release, using
origin.created_origin_hold_ids ∪ cascade.child_hold_ids from the original holdLot
response.
Do not include origin.root_hold_ids blindly in the release set — those may include
pre-existing roots from a prior cascadeLotHold call that this call attached children to,
and releasing them would also release siblings the current caller did not place.
Show child attributes
Show child attributes
Was this page helpful?